# == Schema Information
# Schema version: 157
#
# Table name: workflow_actions
#
#  id          :integer(11)     not null, primary key
#  kind        :string(255)     
#  position    :integer(11)     
#  workflow_id :integer(11)     
#  quantities  :text            
#  operators   :text            
#  operands    :text            
#
class WorkflowAction < ActiveRecord::Base
  @@children = nil
  
  abstract_class     = true
  self.inheritance_column = "kind"
  
  belongs_to   :workflow
  acts_as_list :scope => :workflow
  
  serialize :quantities, Array
  serialize :operators,  Array
  serialize :operands,   Array
  serialize :options, Hash
    
  attr_accessor :input, :connecting_operator
  attr_reader :valid_input_classes, :output, :output_class
    
  def after_initialize
    self.quantities ||= Array.new
    self.operators ||= Array.new
    self.operands ||= Array.new
    self.options ||= Hash.new
  end
    
  def accepts_input?(action)
    accepts = self.valid_input_classes.any? do |klass|
      klass == action.output_class
    end
    
    unless accepts
      output_instance = action.output_class.new
      accepts = self.valid_input_classes.any? do |klass|
        output_instance.kind_of?(klass)
      end
    end
    accepts
  end
  
  def input_class
    if self.input.nil?
      nil
    elsif self.input.kind_of?(Array)
      self.input.first.class
    else
      self.input.class
    end
  end
  
  def has_input?
    ! self.input.nil?
  end
  
  def add_rule(quantity, operator, operand)
    self.quantities << quantity
    self.operators << operator
    self.operands << operand
  end
  
  def remove_rule(quantity)
    index = quantities.index(quantity)
    if index
      [quantities, operators, operands].each do |list|
        list.delete_at(index)
      end
    end
  end
  
  def execute; end
  
  def reset
    self.input = nil
    @output = nil
  end
  
  def conditions
    return nil if self.quantities.blank?
    
    conditions = Array.new
    match_string = String.new
    self.quantities.each_with_index do |quantity, index|
      operator = self.operators[index]
      operand = self.operands[index]
      match_string << " #{self.connecting_operator || 'AND'} " unless index == 0
      match_string << "#{quantity} #{operator} "
      if operand.nil?
        match_string << 'NULL'
      else
        match_string << (operand.kind_of?(Array) ? "(?)" : "?")
      end
    end
    conditions << match_string
    conditions.concat(self.operands)
    return conditions
  end

  # accept a single integer, an array, or a CSV list of IDs 
  def add_id_list_rule(id_list, id_name = nil)
    id_name ||= "id"
    values = if id_list.kind_of?(Array)
      id_list
    elsif id_list.kind_of?(String)
      id_list.gsub(' ', '').split(",")
    else
      [id_list]
    end

    values = values.compact
    self.add_rule(id_name, "IN", values) #unless values.blank?
  end
  
  def input_as_array
     self.input.kind_of?(Array) ? self.input : [self.input]
  end
  
  def method_missing(method, *args)
    if self.respond_to?(method)
      super
    else
      method_name = method.to_s
      if method_name.ends_with?('=') and args.size == 1
        self.options[method_name.chop.to_sym] = args.first
      elsif args.empty?
        self.options[method_name.to_sym]
      else
        super
      end
    end
  end
  
  def self.subclasses
    if @@children.nil?
      require 'find'
      for path in $LOAD_PATH
        Find.find(path) do |file_name|
          next if /\/generators\// =~ file_name
          load file_name if /_action.rb$/ =~ file_name
        end
      end
      @@children = subclasses_of(self)
    end
    @@children
  end
end
